﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Xml.Serialization;
using System.Runtime.Serialization;


namespace MazeWars
{
    public class Tool
    {
        #region Members
        KeyboardState prevState;
        Viewport tilesView, placeView;
        Texture2D tiles, darkTiles;
        Trunk trunk;
        Vector2 offset, newTile;
        Vector2[] orth;
        SaveForm form;
        SpriteFont font;
        Rectangle srcRect;
        int tileType, tileElement;
        string node, notNode;
        #endregion

        #region Ctor
        public Tool()
        {
            tileType = 0;
            tileElement = 0;
            node = "Trunk node";
            notNode = "Trunk tile";
            form = new SaveForm();
            trunk = new Trunk();
            newTile = new Vector2(0, 0);
            offset = new Vector2();
            orth = new Vector2[4];
            orth[0] = new Vector2(0, 64);
            orth[1] = new Vector2(64, 0);
            orth[2] = new Vector2(0, -64);
            orth[3] = new Vector2(-64, 0);
            srcRect = new Rectangle(0, 0, 64, 64);
            trunk.Name = "New trunk";
            trunk.TrunkTiles.Add(new Tile(newTile, tileType, srcRect));
        }
        #endregion

        #region Properties
        public Trunk MyTrunk
        {
            set
            {
                trunk = value;
            }
            get
            {
                return trunk;
            }
        }

        public float X
        {
            set
            {
                newTile.X = value;
            }
            get
            {
                return newTile.X;
            }
        }

        public float Y
        {
            set
            {
                newTile.Y = value;
            }
            get
            {
                return newTile.Y;
            }
        }

        public SaveForm MySaveForm
        {
            set
            {
            }
            get
            {
                return form;
            }
        }
        #endregion     

        #region Load/UnloadContent
        public void loadContent(ContentManager cm, Viewport vp)
        {
            form.setTool(this);
            font = cm.Load<SpriteFont>("Font");
            tiles = cm.Load<Texture2D>("Alpha_TilePallet");
            darkTiles = cm.Load<Texture2D>("Alpha_ColdTilePallet");
            tilesView = vp;
            placeView = vp;
            tilesView.Width = vp.Width * 3 / 4;
            placeView.Width = vp.Width / 4;
            placeView.X = vp.Width * 3 / 4;
            offset.X = tilesView.Width / 2;
            offset.Y = tilesView.Height / 2;
        }

        public void unloadContent()
        {
            form.Dispose();
        }
        #endregion

        #region Update/Draw
        public void update(KeyboardState ks)
        {
            if (ks.IsKeyDown(Keys.D) && prevState.IsKeyUp(Keys.D))
            {
                moveTile(Keys.D);
            }

            if (ks.IsKeyDown(Keys.A) && prevState.IsKeyUp(Keys.A))
            {
                moveTile(Keys.A);
            }

            if (ks.IsKeyDown(Keys.W) && prevState.IsKeyUp(Keys.W))
            {
                moveTile(Keys.W);
            }

            if (ks.IsKeyDown(Keys.S) && prevState.IsKeyUp(Keys.S))
            {
                moveTile(Keys.S);
            }

            if (ks.IsKeyDown(Keys.M) && prevState.IsKeyUp(Keys.M))
            {
                form.Show();
            }

            if (ks.IsKeyDown(Keys.Down) && prevState.IsKeyUp(Keys.Down))
            {
                tileType++;
                if (tileType > 1)
                    tileType = 0;
            }

            if (ks.IsKeyDown(Keys.Up) && prevState.IsKeyUp(Keys.Up))
            {
                tileType--;
                if (tileType < 0)
                    tileType = 1;
            }

            if (ks.IsKeyDown(Keys.Left) && prevState.IsKeyUp(Keys.Left))
            {
                changeElement(Keys.Left);
            }

            if (ks.IsKeyDown(Keys.Right) && prevState.IsKeyUp(Keys.Right))
            {
                changeElement(Keys.Right);
            }

            prevState = ks;
        }

        public void draw(SpriteBatch sb, GraphicsDevice gd)
        {
            gd.Viewport = tilesView;
            gd.Clear(Color.White);
            
            sb.Begin();
            
            foreach (Tile tile in trunk.TrunkTiles)
            {
                sb.Draw(tiles, tile.Pos + offset, tile.SrcRect, Color.White);
            }
            sb.DrawString(font, trunk.Name, new Vector2(tilesView.Width / 2, tilesView.Height / 6), Color.Black);
            
            sb.End();

            gd.Viewport = placeView;
            gd.Clear(Color.White);

            switch (tileElement)
            {
                case 0: srcRect.X = 0; srcRect.Y = 0; break;
                case 1: srcRect.X = 256; srcRect.Y = 0; break;
                case 2: srcRect.X = 512; srcRect.Y = 0; break;
                case 3: srcRect.X = 768; srcRect.Y = 0; break;
                case 4: srcRect.X = 0; srcRect.Y = 640; break;
                case 5: srcRect.X = 256; srcRect.Y = 640; break;
                case 6: srcRect.X = 512; srcRect.Y = 640; break;
                case 7: srcRect.X = 768; srcRect.Y = 640; break;    
            }

            sb.Begin();

            if (tileType == 0)
            {
                sb.Draw(tiles, new Vector2(placeView.Width / 2 - 32, placeView.Height / 3), srcRect, Color.White);
                srcRect.Y += 128;
                sb.Draw(darkTiles, new Vector2(placeView.Width / 2 - 32, placeView.Height * 2 / 3), srcRect, Color.White);
            }
            else
            {
                sb.Draw(darkTiles, new Vector2(placeView.Width / 2 - 32, placeView.Height / 3), srcRect, Color.White);
                srcRect.Y += 128;
                sb.Draw(tiles, new Vector2(placeView.Width / 2 - 32, placeView.Height * 2 / 3), srcRect, Color.White);
            }
            sb.DrawString(font, notNode, new Vector2(placeView.Width / 2 - 32, placeView.Height / 3 - 20), Color.Black);
            sb.DrawString(font, node, new Vector2(placeView.Width / 2 - 32, placeView.Height * 2 / 3 - 20), Color.Black);

            sb.End();
        }
        #endregion

        #region HelperFunctions
        public void reset()
        {
            newTile.X = 0;
            newTile.Y = 0;
            trunk = new Trunk();
            trunk.Name = "New trunk";
            srcRect.X = 0;
            srcRect.Y = 0;
            tileType = 0;
            trunk.TrunkTiles.Add(new Tile(newTile, tileType, srcRect));
        }

        private void moveTile(Keys key)
        {
            int counter = 0;
            switch (key)
            {
                case Keys.A: newTile.X -= 64; break;
                case Keys.D: newTile.X += 64; break;
                case Keys.W: newTile.Y -= 64; break;
                case Keys.S: newTile.Y += 64; break;
            }

            for (int i = 0; i < trunk.TrunkTiles.Count; i++)
            {
                if (trunk.TrunkTiles[i].Pos == newTile)
                {
                    trunk.TrunkTiles.RemoveRange(i, trunk.TrunkTiles.Count - i);
                    break;
                }
                else
                {
                    for (int j = 0; j < 4; j++)
                    {
                        if (trunk.TrunkTiles[i].Pos == newTile + orth[j])
                        {
                            counter++;
                        }
                    }
                    if (counter > 1)
                    {
                        switch (key)
                        {
                            case Keys.A: newTile.X += 64; break;
                            case Keys.D: newTile.X -= 64; break;
                            case Keys.W: newTile.Y += 64; break;
                            case Keys.S: newTile.Y -= 64; break;
                        }
                        break;
                    }
                }
            }

            if (counter < 2)
            {
                switch (tileElement)
                {
                    case 0: srcRect.X = 0; srcRect.Y = 0; break;
                    case 1: srcRect.X = 256; srcRect.Y = 0; break;
                    case 2: srcRect.X = 512; srcRect.Y = 0; break;
                    case 3: srcRect.X = 768; srcRect.Y = 0; break;
                    case 4: srcRect.X = 0; srcRect.Y = 640; break;
                    case 5: srcRect.X = 256; srcRect.Y = 640; break;
                    case 6: srcRect.X = 512; srcRect.Y = 640; break;
                    case 7: srcRect.X = 768; srcRect.Y = 640; break;
                }
                if (trunk.TrunkTiles.Count != 0 && trunk.TrunkTiles[trunk.TrunkTiles.Count - 1].Type == 1)
                {
                    tileType = 0;
                }
                if (tileType == 1)
                {
                    srcRect.Y += 128;
                }
                trunk.TrunkTiles.Add(new Tile(newTile, tileElement * 2 + tileType, srcRect));
            }
        }

        private void changeElement(Keys key)
        {
            switch (key)
            {
                case Keys.Left:
                {
                    tileElement--;
                    if (tileElement < 0)
                        tileElement = 7;
                } break;
                case Keys.Right:
                {
                    tileElement++;
                    if (tileElement > 7)
                        tileElement = 0;
                } break;
            }

            foreach (Tile t in trunk.TrunkTiles)
            {
                t.Type = tileElement * 2 + t.Type % 2;
                switch (tileElement)
                {
                    case 0: srcRect.X = 0; srcRect.Y = 0; break;
                    case 1: srcRect.X = 256; srcRect.Y = 0; break;
                    case 2: srcRect.X = 512; srcRect.Y = 0; break;
                    case 3: srcRect.X = 768; srcRect.Y = 0; break;
                    case 4: srcRect.X = 0; srcRect.Y = 640; break;
                    case 5: srcRect.X = 256; srcRect.Y = 640; break;
                    case 6: srcRect.X = 512; srcRect.Y = 640; break;
                    case 7: srcRect.X = 768; srcRect.Y = 640; break;
                }
                if (t.Type % 2 == 1)
                    srcRect.Y += 128;
                t.SrcRect = srcRect;
            }

            switch (tileElement)
            {
                case 0: notNode = "Trunk tile"; node = "Trunk node"; break;
                case 1: notNode = "Fire tile"; node = "Fire node"; break;
                case 2: notNode = "Water tile"; node = "Water node"; break;
                case 3: notNode = "Wind tile"; node = "Wind node"; break;
                case 4: notNode = "Earth tile"; node = "Earth node"; break;
                case 5: notNode = "Lightning tile"; node = "Lightning node"; break;
                case 6: notNode = "Light tile"; node = "Light node"; break;
                case 7: notNode = "Shadow tile"; node = "Shadow node"; break;
            }
        }
        #endregion
    }//End of class Tool
}
